﻿#include "dlgreport.h"
#include "ui_dlgreport.h"
#include "globalsymbol.h"

#include <QDebug>
#include <QDateTime>
#include <QFile>
#include <QMessageBox>
#include <QPrintPreviewDialog>
#include <QProgressDialog>
#include <QPainter>
#include <QtPrintSupport>
#include <QtConcurrent>
#include <QFutureWatcher>

DlgReport::DlgReport(QSettings* settings, JsonConfig* jsonConfig, QString subflowId, const QString& reportFileName, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DlgReport),
    m_settings(settings),
    m_jsonConfig(jsonConfig),
    m_subflowId(subflowId),
    m_reportFileName(reportFileName)
{
    ui->setupUi(this);

    // 初始化
    initUI();
    initGraphics();
    init();
}

DlgReport::~DlgReport()
{
    delete ui;
}

void DlgReport::initUI()
{
    setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint);

    connect(ui->btnPrintPreview,  &QPushButton::clicked, this, &DlgReport::onPrintPreview);
    connect(ui->btnSave, &QPushButton::clicked, this, &DlgReport::onSave);
    connect(ui->btnCancel, &QPushButton::clicked, this, [=](){this->reject();});
}

void DlgReport::initGraphics()
{
    m_scene = new QGraphicsScene;
    // 初始时, 把场景的宽度设置为和视图等长的固定宽度, 场景的高度设置为一个很大的值, 待绘制完成后在把根据场景的实际有效高度进行设置.
    m_scene->setSceneRect(0, 0, 920, 102400);
    // 设置背景底色
    m_scene->setBackgroundBrush(Qt::white);

    // 抗锯齿效果
    ui->gvReport->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing);
    ui->gvReport->setCacheMode(QGraphicsView::CacheBackground);
    ui->gvReport->setScene(m_scene);
    //ui->gvReport->fitInView(m_scene->sceneRect());
    // 视图中心左上角
    ui->gvReport->centerOn(0, 0);
    // 隐藏水平滚动条
    ui->gvReport->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    // 从高度0开始
    m_currentY = 0;
}

void DlgReport::init()
{
    // 读取报表数据文件
    readData();

    int level = m_systemSetList.first().toInt();
    if (m_subflowId.startsWith("11") || m_subflowId.startsWith("21")) {
        // 系统设置
        addSystemSet(level, QStringLiteral("伺服机构测试"));

        if (m_subflowId.startsWith("111") || m_subflowId.startsWith("211")) {
            // 静态测试: 零位
            addZeroPositionStatic(level);
        } else {
            // 零位
            addZeroPosition(level);
            // 启动特性(建压时间)
            addPressureFeature(level);
            // 极性检查
            addPolarFeature();
            // 位置特性
            addPositionFeature(level);
            // 暂态特性
            addTransientFeature(level);
            // 频率特性: 幅值, 相角
            addFreq(level);
        }
    }

    if (m_subflowId.startsWith("12") || m_subflowId.startsWith("22")) {
        // 系统设置
        addSystemSet(level, QStringLiteral("伺服系统测试"));
        // 位置特性
        addPositionFeature(level);
        // 位置特性一路零指令
        addPositionFeature1(level);
        // 位置特性二路零指令
        addPositionFeature2(level);
        // 位置特性三路零指令
        addPositionFeature3(level);
    }

    // 报表生成后, 把高度设置为有效的高度
    m_scene->setSceneRect(0, 0, 920, m_currentY + 30);
}

void DlgReport::readData()
{
    // 读取报表数据文件
    QStringList reportValueList;
    QFile file(m_reportFileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QMessageBox::critical(this, QStringLiteral("错误"), QStringLiteral("报表数据读取错误!"));
        return;
    }
    QTextStream stream(&file);
    while (!stream.atEnd()) {
        QString line = stream.readLine();
        reportValueList << line;
    }

    // 前14行是系统设置, 第13行是伺服机构选择列表
    for (int i = 0; i < 14; i++) {
        m_systemSetList << reportValueList.at(i);
        m_reportValueList << QStringList();
    }
    m_machineList = m_systemSetList.last().split(",");

    // 第14行至最后1行是4个伺服机构的模拟数据
    for (int i = 14; i < reportValueList.length(); i++) {
        m_reportValueList << reportValueList.at(i).split(",");
    }
}

void DlgReport::addSystemSet(const int level, const QString type)
{
    // 标题
    QString title;
    switch (level) {
    case 1:
        title = QStringLiteral("一级");
        break;
    case 2:
        title = QStringLiteral("二级");
        break;
    default:
        break;
    }
    title.append(QStringLiteral("%1_单元测试报告").arg(type));

    // 测试日期
    QString dateString = m_reportFileName.right(23).chopped(4);

    QStringList valueList;
    valueList << title
              << m_systemSetList.at(2) << m_systemSetList.at(8) << m_systemSetList.at(9)
              << m_systemSetList.at(10) << dateString
              << m_systemSetList.at(3) << m_systemSetList.at(4) << m_systemSetList.at(5) << m_systemSetList.at(6) << m_systemSetList.at(7)
              << m_jsonConfig->deviceId() << m_jsonConfig->version()
              << m_systemSetList.at(12);

    SystemSetItem* systemSetItem = new SystemSetItem(valueList, this);
    systemSetItem->setPos(0, m_currentY + 20);
    m_scene->addItem(systemSetItem);
    // 记录Y方向的位置坐标
    m_currentY += 400;
}

void DlgReport::addZeroPositionStatic(const int level)
{
    // 静态测试非零位的模拟数据
    QList<QStringList> valueList;
    for (int i = 14; i < 16; i++)
        valueList << m_reportValueList.at(i);

    ZeroPositionStaticItem* zeroPositionStaticItem = new ZeroPositionStaticItem(level, m_machineList, valueList, this);
    zeroPositionStaticItem->setPos(0, m_currentY + 20);
    m_scene->addItem(zeroPositionStaticItem);
    // 记录Y方向的位置坐标
    m_currentY += 240;
}

void DlgReport::addZeroPosition(const int level)
{
    // 零位的模拟数据
    QList<QStringList> valueList;
    for (int i = 14; i < 24; i++)
        valueList << m_reportValueList.at(i);

    ZeroPositionItem* zeroPositionItem = new ZeroPositionItem(level, m_machineList, valueList, this);
    zeroPositionItem->setPos(0, m_currentY + 20);
    m_scene->addItem(zeroPositionItem);
    // 记录Y方向的位置坐标
    m_currentY += 480;
}

void DlgReport::addPressureFeature(const int level)
{
    PressureFeatureItem* pressureFeatureItem = new PressureFeatureItem(level, m_machineList, m_reportValueList.at(24), this);
    pressureFeatureItem->setPos(0, m_currentY + 20);
    m_scene->addItem(pressureFeatureItem);
    // 记录Y方向的位置坐标
    m_currentY += 200;
}

void DlgReport::addPolarFeature()
{
    PolarFeatureItem* polarFeatureItem = new PolarFeatureItem(m_machineList, this);
    polarFeatureItem->setPos(0, m_currentY + 20);
    m_scene->addItem(polarFeatureItem);
    // 记录Y方向的位置坐标
    m_currentY += 200;
}

void DlgReport::addTransientFeature(const int level)
{
    TransientFeatureItem* transientFeatureItem = new TransientFeatureItem(level, m_machineList, m_reportValueList.at(29), this);
    transientFeatureItem->setPos(0, m_currentY + 20);
    m_scene->addItem(transientFeatureItem);
    // 记录Y方向的位置坐标
    m_currentY += 200;
}

void DlgReport::addPositionFeature(const int level)
{
    // 位置特性的模拟数据
    QList<QStringList> valueList;
    for (int i = 25; i < 29; i++)
        valueList << m_reportValueList.at(i);

    PositionFeatureItem* positionFeatureItem = new PositionFeatureItem(level, m_machineList, valueList, this);
    positionFeatureItem->setPos(0, m_currentY + 20);
    m_scene->addItem(positionFeatureItem);
    // 记录Y方向的位置坐标
    m_currentY += 240;
}

void DlgReport::addPositionFeature1(const int level)
{
    // 位置特性的模拟数据
    QList<QStringList> valueList;
    for (int i = 30; i < 34; i++)
        valueList << m_reportValueList.at(i);

    PositionFeature1Item* positionFeature1Item = new PositionFeature1Item(level, m_machineList, valueList, this);
    positionFeature1Item->setPos(0, m_currentY + 20);
    m_scene->addItem(positionFeature1Item);
    // 记录Y方向的位置坐标
    m_currentY += 240;
}

void DlgReport::addPositionFeature2(const int level)
{
    // 位置特性的模拟数据
    QList<QStringList> valueList;
    for (int i = 34; i < 38; i++)
        valueList << m_reportValueList.at(i);

    PositionFeature2Item* positionFeature2Item = new PositionFeature2Item(level, m_machineList, valueList, this);
    positionFeature2Item->setPos(0, m_currentY + 20);
    m_scene->addItem(positionFeature2Item);
    // 记录Y方向的位置坐标
    m_currentY += 240;
}

void DlgReport::addPositionFeature3(const int level)
{
    // 位置特性的模拟数据
    QList<QStringList> valueList;
    for (int i = 38; i < 42; i++)
        valueList << m_reportValueList.at(i);

    PositionFeature3Item* positionFeature3Item = new PositionFeature3Item(level, m_machineList, valueList, this);
    positionFeature3Item->setPos(0, m_currentY + 20);
    m_scene->addItem(positionFeature3Item);
    // 记录Y方向的位置坐标
    m_currentY += 240;
}

void DlgReport::addFreq(const int level)
{
    switch (level) {
    case 1: {
        // 1级频率特性1°幅值的模拟数据
        QList<QStringList> valueList;
        for (int i = 42; i < 51; i++)
            valueList << m_reportValueList.at(i);

        FreqA11Item* freq11AItem = new FreqA11Item(m_machineList, valueList, this);
        freq11AItem->setPos(0, m_currentY + 20);
        m_scene->addItem(freq11AItem);
        // 记录Y方向的位置坐标
        m_currentY += 480;

        // 1级频率特性1°相角的模拟数据
        valueList.clear();
        for (int i = 51; i < 60; i++)
            valueList << m_reportValueList.at(i);

        FreqW11Item* freq11WItem = new FreqW11Item(m_machineList, valueList, this);
        freq11WItem->setPos(0, m_currentY + 20);
        m_scene->addItem(freq11WItem);
        // 记录Y方向的位置坐标
        m_currentY += 480;

        // 1级频率特性2°幅值的模拟数据
        valueList.clear();
        for (int i = 60; i < 62; i++)
            valueList << m_reportValueList.at(i);

        FreqA12Item* freq12AItem = new FreqA12Item(m_machineList, valueList, this);
        freq12AItem->setPos(0, m_currentY + 20);
        m_scene->addItem(freq12AItem);
        // 记录Y方向的位置坐标
        m_currentY += 280;

        // 1级频率特性2°相角的模拟数据
        valueList.clear();
        for (int i = 62; i < 64; i++)
            valueList << m_reportValueList.at(i);

        FreqW12Item* freq12WItem = new FreqW12Item(m_machineList, valueList, this);
        freq12WItem->setPos(0, m_currentY + 20);
        m_scene->addItem(freq12WItem);
        // 记录Y方向的位置坐标
        m_currentY += 280;
    }
        break;
    case 2: {
        // 2级频率特性2°幅值的模拟数据
        QList<QStringList> valueList;
        for (int i = 64; i < 73; i++)
            valueList << m_reportValueList.at(i);

        FreqA22Item* freq22AItem = new FreqA22Item(m_machineList, valueList, this);
        freq22AItem->setPos(0, m_currentY + 20);
        m_scene->addItem(freq22AItem);
        // 记录Y方向的位置坐标
        m_currentY += 480;

        // 2级频率特性2°相角的模拟数据
        valueList.clear();
        for (int i = 73; i < 82; i++)
            valueList << m_reportValueList.at(i);

        FreqW22Item* freq22WItem = new FreqW22Item(m_machineList, valueList, this);
        freq22WItem->setPos(0, m_currentY + 20);
        m_scene->addItem(freq22WItem);
        // 记录Y方向的位置坐标
        m_currentY += 480;

        // 2级频率特性4°幅值的模拟数据
        valueList.clear();
        for (int i = 82; i < 85; i++)
            valueList << m_reportValueList.at(i);

        FreqA24Item* freqA24Item = new FreqA24Item(m_machineList, valueList, this);
        freqA24Item->setPos(0, m_currentY + 20);
        m_scene->addItem(freqA24Item);
        // 记录Y方向的位置坐标
        m_currentY += 360;

        // 2级频率特性4°相角的模拟数据
        valueList.clear();
        for (int i = 85; i < 88; i++)
            valueList << m_reportValueList.at(i);

        FreqW24Item* freqW24Item = new FreqW24Item(m_machineList, valueList, this);
        freqW24Item->setPos(0, m_currentY + 20);
        m_scene->addItem(freqW24Item);
        // 记录Y方向的位置坐标
        m_currentY += 360;
    }
        break;
    default:
        break;
    }
}

void DlgReport::printPreview(QPrinter *printer)
{
    printer->setPageSize(QPrinter::A4);
    printer->setPageMargins(QMarginsF(20, 20, 0, 0));
    printer->setOrientation(QPrinter::Landscape);

    QPainter painter(printer);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing | QPainter::SmoothPixmapTransform);
    ui->gvReport->render(&painter);
    //m_scene->render(&painter);
}

void DlgReport::onPrintPreview()
{
    // 点击打印预览按钮后禁用
    ui->btnPrintPreview->setEnabled(false);

    QPrinter printer(QPrinter::ScreenResolution);
    // 创建打印预览对话框
    QPrintPreviewDialog dlg(&printer, this);
    dlg.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
    dlg.setFixedSize(900, 600);
    // 当要生成预览页面时, 发射paintRequested()信号
    connect(&dlg, &QPrintPreviewDialog::paintRequested, this, &DlgReport::printPreview);
    if (dlg.exec() == QPrintPreviewDialog::Accepted) {
    }

    // 关闭打印预览对话框后启用
    ui->btnPrintPreview->setEnabled(true);
}

void DlgReport::onSave()
{
    QString defaultFilePath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    QString defaultFileName = QString::fromUtf8("%1/%2.pdf").arg(defaultFilePath, m_reportFileName.right(30).chopped(4));
    QString defaultFileFilter = QStringLiteral("Pdf File(*.pdf)");
    QString filename = QFileDialog::getSaveFileName(this, QStringLiteral("数据报表"), defaultFileName, defaultFileFilter);
    if (filename.isNull())  // 取消保存
        return;

    // 从场景单元中的源矩形映射到设备单元中的目标矩形, render只在目标矩形内绘制
    //auto in = 72.0f;
    //auto source = m_scene->sceneRect();
    //auto scale = printer.resolution() / in;
    //auto page = printer.pageRect(QPrinter::DevicePixel);
    //auto target = QRectF(page.topLeft(), source.size() * scale);
    //target &= page;  // clip target rect to page
    //qDebug() << "****" << page << scale << source << target;

    // 显示报告导出进度条
    QProgressDialog progressDialog(this);
    progressDialog.setLabelText(QStringLiteral("正在保存数据报表文件"));
    progressDialog.setRange(0, 100);
    // 模态窗口
    progressDialog.setWindowModality(Qt::WindowModal);
    // 隐藏取消按钮
    progressDialog.setCancelButton(nullptr);
    //progressDialog.show();

    // future设置给watcher进行监控
    QFutureWatcher<void> watcher;
    connect(&progressDialog, &QProgressDialog::canceled, &watcher, &QFutureWatcher<void>::cancel);
    connect(&watcher, &QFutureWatcher<void>::finished, &progressDialog, &QProgressDialog::reset);
    connect(&watcher, &QFutureWatcher<void>::progressRangeChanged, &progressDialog, &QProgressDialog::setRange);
    connect(&watcher, &QFutureWatcher<void>::progressValueChanged, &progressDialog, &QProgressDialog::setValue);

    // concurrent生成future
    QFuture<void> future = QtConcurrent::run([this, filename]() {
        // 如果使用HighResolution, 耗时将会增加
        QPrinter printer(QPrinter::ScreenResolution);
        printer.setPageSize(QPrinter::A4);
        printer.setFullPage(true);
        printer.setOrientation(QPrinter::Portrait);
        printer.setPageMargins(10, 10, 10, 10, QPrinter::Millimeter);
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName(filename);

        auto in = 72.0f;
        auto scale = printer.resolution() / in;
        auto page = printer.pageRect(QPrinter::DevicePixel);

        QPainter painter;
        if(painter.begin(&printer)) {
            // 72像素英寸的分辨率下A4纸的宽高是595 * 842, 打印1页
            int pageHeight = static_cast<int>(m_scene->sceneRect().width() / 595. * 842.);
            int pageCount = static_cast<int>(m_scene->sceneRect().height() / pageHeight) + 1;
            for (int i = 0; i < pageCount; i++) {
                auto source = QRectF(0,  i * pageHeight, m_scene->sceneRect().width(), pageHeight);
                auto target = QRectF(page.topLeft(), source.size() * scale);
                // clip target rect to page
                target &= page;
                m_scene->render(&painter, target, source);

                // page number
                painter.drawText(QPointF(target.bottomRight().x() * 0.98, target.bottomRight().y() * 0.98), QString::number(i + 1));

                // new print page
                if (i < pageCount - 1)
                    printer.newPage();

                // calculate progress
            }
        }
        painter.end();
    });
    watcher.setFuture(future);

    if (progressDialog.exec()) {
    }

    future.waitForFinished();

    this->close();
}
